home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
L' Effet Pommier 3
/
L'Effet Pommier - Volume 03.iso
/
Programmation
/
gray image 2.1
/
fractal_map.cc
< prev
next >
Wrap
Text File
|
1995-05-31
|
5KB
|
146 lines
// This may look like C code, but it is really -*- C++ -*-
/*
************************************************************************
*
* Generating Fractal Maps
*
* The algorithm is based on (but *only* based on) the following
* explanation described in the "documentation" to program MARS
* (Tim Clarke, tjc1005@hermes.cam.ac.uk, posted in some "games"
* group)
*
* "This is a recursive subdivision, or plasma, fractal. You start of
* with a random height at (0,0) and therefore also at (256,0), (0,256),
* (256,256). Call a routine that takes as input the size and position
* of a square, in the first case the entire map.
* This routine get the heights from the corners of the square it gets
* given. Across each edge (if the map has not been written to at the
* point halfway along that edge), it takes the average of the heights of
* the 2 corners on that edge, applies some noise proportional to the
* length of the edge, and writes the result into the map at a position
* halfway along the edge. The center of the square is the average of the
* four corners+noise.
* The routine then calls itself recursively, splitting each square into
* four quadrants, calling itself for each quadrant until the length of
* the side is 2 pixels.
* This is probably old-hat to many people, but the map is made more
* realistic by blurring [applying some filter to it]
* The colors are done so that the sun is on the horizon to the East:
* Color=A*[ w(u+1,v)-w(u,v) ]+B
* with A and B chosen so that the full range of the palette is used.
* The sky is a similar fractal but without the colour transformation"
* <EOQ>
*
* The first distinction is the present program is that the algorithm
* is iterative rather than recursive. For another thing, our map is
* *NOT* periodic. BTW, it lets us use seeds in every corner of a map
* (which would create "biased" clouds).
*
* Note that a map's pixel value is computed average + noise, scaled up to
* the current dim. So when 2*scale > max pixel value, we've got a problem.
* To get around that, the scale factor of the noise is chosen not
* to exceed max_pixel_value/2.
*
* Since map is not-periodical, if a pixel sticks out of the map,
* we force it within: say, when we need to operate map(2^order,j),
* we actually dealing with map((2^order)-1,j), etc.
*
* $Id: fractal_map.cc,v 2.0 1995/03/16 21:18:01 oleg Exp oleg $
*
************************************************************************
*/
#ifdef __GNUC__
#pragma implementation "fractal_map.h"
#endif
#include "fractal_map.h"
#include <minmax.h>
#include "std.h"
// Get some noise with a dispersion 'scale'
// (which is assumed to be a power of 2)
// and average 0
// Say, if scale=2 return either 0 or 1
// if scale=128, return a random number
// within [-64,63]
// Note, that usually a couple of low-order
// bits of Random() are "less" random;
// therefore, we shift them out.
inline int FractalMap::get_noise(const card scale) const
{
#ifdef __SC__
return ((Random() >> 2) & (scale-1)) - scale/2;
#else
return ( rand() & (scale-1) ) - scale/2;
#endif
}
FractalMap::FractalMap
(const card order, const Seeds& _seeds, const card bits_per_pixel)
: LazyImage(1<<order,1<<order,bits_per_pixel),
seeds(_seeds)
{
if( order < 2 || order > 14 )
_error("Order %d of the desired fractal map is unusual, "
"I prefer something within [2,14]",order);
}
//------------------------------------------------------------------------
// Here where the map is really constructed
void FractalMap::fill_in(IMAGE& im) const
{
const card largest_noise_scale = 1<<(im.q_depth()-1);
const card pixel_mask = (1<<im.q_depth())-1;
const card dim = im.q_nrows();
im(0,0) = seeds.s00; // Seed the map
im(dim-1,0) = seeds.s10;
im(0,dim-1) = seeds.s01;
im(dim-1,dim-1) = seeds.s11;
for(register card scale=dim; scale>1; scale >>= 1)
{
const card scale_half = scale>>1;
const card noise_scale = min(scale,largest_noise_scale);
register int i,j;
for(i=0; i<dim; i += scale)
{
int i_up = min(i+scale,dim-1);
int i_hp = i+scale_half;
int corner00 = im(i,0); // caching
int corner10 = im(i_up,0);
int mid30 = im(i_hp,0) =
(((corner00+corner10)>>1) + get_noise(noise_scale)) & pixel_mask;
for(j=0; j<dim; j += scale)
{
int j_up = min(j+scale,dim-1);
int j_hp = j+scale_half;
const int corner01 = im(i,j_up);
const int corner11 = im(i_up,j_up);
const int mid03 = i == 0 ?
( ((corner00+corner01)>>1) +
get_noise(noise_scale) ) & pixel_mask : im(i,j_hp);
const int mid31 = ( ((corner01+corner11)>>1) +
get_noise(noise_scale) ) & pixel_mask;
const int mid13 = ( ((corner10+corner11)>>1) +
get_noise(noise_scale) ) & pixel_mask;
const int mid33 = ( ((mid30+mid03+mid31+mid13)>>2) +
get_noise(noise_scale) ) & pixel_mask;
im(i_hp,j_up) = mid31;
if( i == 0 )
im(i,j_hp) = mid03;
im(i_up,j_hp) = mid13;
im(i_hp,j_hp) = mid33;
// Note, corner01 for col j becomes
corner00 = corner01; // corner00 for the next j
corner10 = corner11;
mid30 = mid31;
}
}
}
}